//
// Copyright (c) 2016-2018 by Cornell University.  All Rights Reserved.
//
// Permission to use the "TownCrier" software ("TownCrier"), officially
// docketed at the Center for Technology Licensing at Cornell University
// as D-7364, developed through research conducted at Cornell University,
// and its associated copyrights solely for educational, research and
// non-profit purposes without fee is hereby granted, provided that the
// user agrees as follows:
//
// The permission granted herein is solely for the purpose of compiling
// the TownCrier source code. No other rights to use TownCrier and its
// associated copyrights for any other purpose are granted herein,
// whether commercial or non-commercial.
//
// Those desiring to incorporate TownCrier software into commercial
// products or use TownCrier and its associated copyrights for commercial
// purposes must contact the Center for Technology Licensing at Cornell
// University at 395 Pine Tree Road, Suite 310, Ithaca, NY 14850; email:
// ctl-connect@cornell.edu; Tel: 607-254-4698; FAX: 607-254-5454 for a
// commercial license.
//
// IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF TOWNCRIER AND ITS
// ASSOCIATED COPYRIGHTS, EVEN IF CORNELL UNIVERSITY MAY HAVE BEEN
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE WORK PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND CORNELL
// UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
// ENHANCEMENTS, OR MODIFICATIONS.  CORNELL UNIVERSITY MAKES NO
// REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER IMPLIED
// OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE
// OF TOWNCRIER AND ITS ASSOCIATED COPYRIGHTS WILL NOT INFRINGE ANY
// PATENT, TRADEMARK OR OTHER RIGHTS.
//
// TownCrier was developed with funding in part by the National Science
// Foundation (NSF grants CNS-1314857, CNS-1330599, CNS-1453634,
// CNS-1518765, CNS-1514261), a Packard Fellowship, a Sloan Fellowship,
// Google Faculty Research Awards, and a VMWare Research Award.
//

#include <stdint.h>
#include "eth_abi.h"
#include "commons.h"
#include "external/keccak.h"
#include "debug.h"

int ABI_UInt64::encode(bytes &out) {
  return append_as_uint256(out, this->_data, 8);
}

int ABI_UInt8::encode(bytes &out) {
  return append_as_uint256(out, this->_data, 1);
}

int ABI_UInt32::encode(bytes &out) {
  return append_as_uint256(out, this->_data, 4);
}

int ABI_Address::encode(bytes &out) {
  out.insert(out.end(), 12, 0);
  for (int i = 0; i < 20; i++) {
    out.push_back((*this->_data)[i]);
  }
  return 0;
}

int ABI_Bytes32::encode(bytes &out) {
  for (int i = 0; i < 32; i++) {
    out.push_back((*this->_data)[i]);
  }
  return 0;
}

int ABI_Bytes::encode(bytes &out) {
  if (append_as_uint256(out, this->_data.size(), 4) != 0) {
    printf_sgx("Error! enc(out, int) return non-zero!\n");
    return -1;
  }
  // padding left
  for (size_t i = 0; i < ROUND_TO_32(this->_data.size()) - this->_data.size(); i++) { out.push_back(0); }
  out.insert(out.end(), this->_data.begin(), this->_data.end());
  return 0;
}

//template<class T>
//int ABI_T_Array<T>::encode(bytes& out)
//{
//    if (append_as_uint256(out, this->items.size(), 4) != 0) {printf_sgx("Error! enc(out, int) return non-zero!\n"); return -1;}
//    for (size_t i = 0; i < this->items.size(); i++)
//    {
//        if (items[i]->encode(out)) return -1;
//    }
//    return 0;
//}

//template<class T>
//int ABI_T_Array<T>::encode_len()
//{
//    int len = 32;
//    for (size_t i = 0; i < items.size(); i++)
//    {
//        len += this->items[i]->encode_len();
//    }

//    return len;
//}

#include "log.h"

int ABI_Generic_Array::encode(bytes &out) {
  size_t i, j;
  size_t head_len_sum = 0;
  size_t tail_len_sum = 0;
  for (i = 0; i < this->items.size(); i++) { head_len_sum += this->items[i]->head_len(); }

  // head encoding
  for (i = 0; i < this->items.size(); i++) {
    if (this->items[i]->dynamic()) {
      for (j = 0; j < i; j++) {
        tail_len_sum += this->items[j]->tail_len();
      }
      if (append_as_uint256(out, head_len_sum + tail_len_sum, sizeof(size_t)) != 0) { return -1; }
    } else {
      if (this->items[i]->encode(out)) {
        LL_CRITICAL("Error");
        return -1;
      }
    }
  }

  // tail encoding
  for (i = 0; i < this->items.size(); i++) {
    if (this->items[i]->dynamic()) {
      if (this->items[i]->encode(out)) { return -1; };
    }
  }

  return 0;
}

int ABI_Generic_Array::encode_len() {
  int len = 32;
  for (size_t i = 0; i < items.size(); i++) {
    len += this->items[i]->encode_len();
  }

  return len;
}
